package net.wy.util.image;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.awt.image.renderable.ParameterBlock;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
import javax.media.jai.Interpolation;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.RenderedOp;

import net.wy.commons.util.AssertExt;

import org.apache.commons.io.FilenameUtils;

import com.sun.imageio.plugins.jpeg.JPEGImageWriter;
import com.sun.media.jai.codec.FileSeekableStream;
import com.sun.media.jai.codec.ImageCodec;
import com.sun.media.jai.codec.ImageEncoder;

/**
 * Created with IntelliJ IDEA.
 * User: Administrator
 * Date: 12-9-25
 * Time: 上午10:09
 * 图片操作工具类
 */
public class ImageUtils {
    public static final String IMAGE_TYPE_BMP = "BMP";
    public static final String IMAGE_TYPE_GIF = "GIF";
    public static final String IMAGE_TYPE_JPEG = "JPEG";
    public static final String IMAGE_TYPE_JPG = "JPG";
    public static final String IMAGE_TYPE_PNG = "PNG";
    public static final String IMAGE_TYPE_PNM = "PNM";
    public static final String IMAGE_TYPE_TIFF = "TIFF";

    /**
     * 生成图片大小
     * @param img
     * @param width
     * @param height
     * @return
     */
    private static Image changSize(Image img, int width, int height) {
        int w = img.getWidth(null);
        int h = img.getHeight(null);

        if (w <= width && h <= height) {
        } else {
            if (w == h) {//实际宽度等于实际高度
                if (width >= height) {//大于或等于
                    if (height == 0) {
                        float scale = new BigDecimal(h).divide(new BigDecimal(w), 10, RoundingMode.HALF_DOWN).floatValue();
                        h = (int) (h * scale);
                    } else {
                        h = height;
                    }
                    w = h;
                } else {//小于高度大于宽度
                    w = width;
                    h = w;
                }
            } else if (w > h) {
                float scale = new BigDecimal(h).divide(new BigDecimal(w), 10, RoundingMode.HALF_DOWN).floatValue();
                w = width;
                h = (int) (w * scale);
            } else {
                float scale = new BigDecimal(w).divide(new BigDecimal(h), 10, RoundingMode.HALF_DOWN).floatValue();
                if (height == 0) {
                    float scale1 = new BigDecimal(w).divide(new BigDecimal(h), 10, RoundingMode.HALF_DOWN).floatValue();
                    h = (int) (h * scale1);
                } else {
                    h = height;
                }
                w = (int) (h * scale);
            }
        }

        img = img.getScaledInstance(w, h, 4);
        return img;
    }

    /**
     * 判断文件是否为图片格式
     * @param file
     * @return
     */
    public static boolean isImage(File file){
        if (file == null || !file.exists() || !file.isFile()) {
            return false;
        }

        byte[] b = new byte[4];
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
            fileInputStream.read(b, 0, b.length);
        } catch (IOException e) { }
        finally{
            if( fileInputStream != null ){
                try{
                    fileInputStream.close();
                }catch(IOException e){}
            }
        }

        String type = ImageUtils.bytesToHexString(b).toUpperCase();
        if(type.contains("FFD8FF")) {
            // "jpg";
            return true;
        } else if (type.contains("89504E47")) {
            // "png";
            return true;
        } else if (type.contains("47494638")) {
            // "gif";
            return true;
            //} else if (type.contains("49492A00")) {
            //	// "tif";
            //	return true;
        } else if (type.contains("424D")) {
            // "bmp";
            return true;
        }else{
            return false;
        }
    }

    /**
     * byte数组转换成16进制字符串
     * @param src
     * @return
     */
    private static String bytesToHexString(byte[] src) {
        if (src == null || src.length == 0) {
            return "";
        }

        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    private static BufferedImage toBufferedImage(Image img) {
        int w = img.getWidth(null);
        int h = img.getHeight(null);
        BufferedImage bi = new BufferedImage(w, h, 1);
        Graphics2D g = bi.createGraphics();
        g.setBackground(Color.WHITE);
        g.fillRect(0, 0, w, h);

        bi.getGraphics().drawImage(img, 0, 0, w, h, null);
        return bi;
    }

    private static BufferedImage toBufferedImage(Image img, int x, int y) {
        int w = img.getWidth(null);
        int h = img.getHeight(null);
        BufferedImage bi = new BufferedImage(w, h, 1);
        Graphics2D g = bi.createGraphics();
        g.setBackground(Color.WHITE);
        g.clearRect(0, 0, w, h);
        bi.getGraphics().drawImage(img, x, y, null);
        return bi;
    }

    /**
     * 剪切图片大小
     * @param file
     * @param x
     * @param y
     * @param w
     * @param h
     * @return
     * @throws IOException
     */
    public static BufferedImage toCroppedImage(File file, int x, int y, int w, int h) throws IOException {
        BufferedImage outImage = ImageIO.read(file);
        BufferedImage cropped = outImage.getSubimage(x, y, w, h);
        return cropped;
    }

    /**
     * 生成JPG
     * @param bi
     * @param dest
     * @throws IOException
     */
    private static void toJPEG(BufferedImage bi, File dest)
            throws IOException {
        JPEGImageWriter imageWriter = (JPEGImageWriter) ImageIO.getImageWritersBySuffix("jpeg").next();
        ImageOutputStream ios = ImageIO.createImageOutputStream(dest);
        imageWriter.setOutput(ios);

        JPEGImageWriteParam jpegParams = (JPEGImageWriteParam) imageWriter.getDefaultWriteParam();
        jpegParams.setCompressionMode(2);

        jpegParams.setCompressionQuality(1.0F);
        IIOMetadata data = imageWriter.getDefaultImageMetadata(new ImageTypeSpecifier(bi), jpegParams);

        imageWriter.write(data, new IIOImage(bi, null, null), jpegParams);
        ios.close();
        imageWriter.dispose();
    }

    /**
     * 生成GIF
     * @param src
     * @param dest
     * @param width
     * @param height
     */
    private static void toActiveGIF(File src, File dest, int width, int height) {
        GifDecoder decoder = new GifDecoder();
        decoder.read(src.getPath());
        int n = decoder.getFrameCount();
        ArrayList biList = new ArrayList();
        ArrayList delayList = new ArrayList();
        for (int i = 0; i < n; i++) {
            BufferedImage bi = decoder.getFrame(i);

            Image img = changSize(bi, width, height);
            bi = toBufferedImage(img);
            biList.add(bi);
            int delay = decoder.getDelay(i);
            delayList.add(Integer.valueOf(delay));
        }

        AnimatedGifEncoder e = new AnimatedGifEncoder();
        e.setRepeat(0);
        e.start(dest.getPath());
        for (int i = 0; i < biList.size(); i++) {
            e.setDelay(((Integer) delayList.get(i)).intValue());
            e.addFrame((BufferedImage) biList.get(i));
        }
        e.finish();
    }

    /**
     * 生成PNG
     * @param src
     * @param dest
     * @param width
     * @param height
     * @throws IOException
     */
    private static void toPNG(File src, File dest, int width, int height)
            throws IOException {
        Image img = changSize(ImageIO.read(src), width, height);
        PlanarImage pi = loadImage(src.getPath(), img.getWidth(null), img.getHeight(null));
        FileOutputStream fout = new FileOutputStream(dest.getPath());
        encodeImage(pi, fout);
    }

    private static PlanarImage loadImage(String imageName, int width, int height)
            throws IOException {
        FileSeekableStream stream = new FileSeekableStream(imageName);

        RenderedOp image1 = JAI.create("stream", stream);
        int sourceImageWidth = image1.getWidth();
        int sourceImageHeight = image1.getHeight();

        Interpolation interpolation = Interpolation.getInstance(0);

        ParameterBlock params = new ParameterBlock();
        params.addSource(image1);
        float xscale = width / sourceImageWidth;
        float yscale = height / sourceImageHeight;

        params.add(new Float(xscale));
        params.add(new Float(yscale));
        params.add(new Float(0.0F));
        params.add(new Float(0.0F));
        params.add(interpolation);

        PlanarImage src = JAI.create("scale", params);
        return src;
    }

    private static void encodeImage(PlanarImage img, FileOutputStream out) throws IOException {
        ImageEncoder encoder = ImageCodec.createImageEncoder("png", out, null);
        encoder.encode(img);
        out.close();
    }

    private static void toOther(String imageType, BufferedImage bi, File dest)
            throws IOException {
        ImageIO.write(bi, imageType, dest);
    }

    public static boolean doChangeSize(String imageType, File src, File dest, int width, int height)
            throws IOException {
        AssertExt.hasLength(imageType);
        AssertExt.isTrue((src != null) && (src.exists()), "source Image File not exist!");
        AssertExt.notNull(dest);
        AssertExt.isTrue((width > 0) && (height > 0));
        AssertExt.hasLength(imageType);

        if (imageType.equalsIgnoreCase("GIF")) {
            toActiveGIF(src, dest, width, height);
            return true;
        }

        Image img = ImageIO.read(src);
        img = changSize(img, width, height);
        BufferedImage bi = toBufferedImage(img);
        if ((imageType.equalsIgnoreCase("JPEG")) || (imageType.equalsIgnoreCase("JPG"))) {
            toJPEG(bi, dest);
            return true;
        }
        if (imageType.equalsIgnoreCase("PNG")) {
            toPNG(src, dest, width, height);
            return true;
        }
        toOther(imageType, bi, dest);
        return true;
    }

    public static boolean doChangeSize(String imageType, File src, File dest, int width, int height, int x, int y) throws IOException {
        AssertExt.hasLength(imageType);
        AssertExt.isTrue((src != null) && (src.exists()), "source Image File not exist!");
        AssertExt.notNull(dest);
        AssertExt.isTrue((width > 0) && (height > 0));
        AssertExt.hasLength(imageType);

        if (imageType.equalsIgnoreCase("GIF")) {
            toActiveGIF(src, dest, width, height);
            return true;
        }

        Image img = ImageIO.read(src);

        BufferedImage bi = toCroppedImage(src, x, y, width, height);
        if (imageType.equalsIgnoreCase("JPEG")) {
            toJPEG(bi, dest);
            return true;
        }
        if (imageType.equalsIgnoreCase("PNG")) {
            toPNG(src, dest, width, height);
            return true;
        }
        toOther(imageType, bi, dest);
        return true;
    }

    public static Map<String, File> genPictures(java.util.List<int[]> sizes, File src, File destDir)
            throws IOException {
        AssertExt.isTrue((src != null) && (src.exists()), "src Image File no exist!");
        AssertExt.notNull(sizes);

        File realDestDir = null;
        if (destDir != null) {
            realDestDir = destDir;
            if (!destDir.exists())
                AssertExt.isTrue(destDir.mkdirs());
        } else {
            realDestDir = src.getParentFile();
        }

        String fileName = src.getName();
        HashMap files = new HashMap();
        for (int[] size : sizes) {
            String sizeStr = size[0] + "X" + size[1];
            File newFile = new File(realDestDir, ImageUtils.insertFileNameSuffixToUrl(fileName, "_" + sizeStr));
            doChangeSize(FilenameUtils.getExtension(fileName), src, newFile, size[0], size[1]);
            files.put(sizeStr, newFile);
        }
        return files;
    }
    
    public static String insertFileNameSuffixToUrl(String url, String suffix) {
        int index = url.lastIndexOf(46);
        if (index > 0) {
            StringBuilder sb = new StringBuilder(url);
            sb.insert(index, suffix);
            return sb.toString();
        }
        return url;
    }

    public static void addWaterMark(String imageType, File src, File waterMarkSrc) {
        try {
            Image iSrc = ImageIO.read(src);
            int width = iSrc.getWidth(null);
            int height = iSrc.getHeight(null);

            BufferedImage bi = null;
            bi = new BufferedImage(width, height, 1);
            Graphics2D g = bi.createGraphics();
            g.setBackground(Color.WHITE);
            g.fillRect(0, 0, width, height);

            g.drawImage(iSrc, 0, 0, width, height, null);

            Image iWMSrc = ImageIO.read(waterMarkSrc);
            int wmWidth = iWMSrc.getWidth(null);
            int wmHeight = iWMSrc.getHeight(null);
            int w = 0;
            int h = 0;

            double scale = 1.0D;
            if (wmWidth > wmHeight)
                scale = wmHeight / wmWidth;
            else {
                scale = wmWidth / wmHeight;
            }

            if (width > height) {
                if (wmWidth > wmHeight) {
                    if (wmWidth > width) {
                        wmWidth = width;
                    }
                    wmHeight = new Double(wmWidth * scale).intValue();
                } else {
                    if (wmHeight > height) {
                        wmHeight = height;
                    }
                    wmWidth = new Double(wmHeight * scale).intValue();
                }
            } else if (wmHeight > wmWidth) {
                if (wmHeight > height) {
                    wmHeight = height;
                }
                wmWidth = new Double(wmHeight * scale).intValue();
            } else {
                if (wmWidth > width) {
                    wmWidth = width;
                }
                wmHeight = new Double(wmWidth * scale).intValue();
            }

            if (width > wmWidth) {
                w = (width - wmWidth) / 2;
            }
            if (height > wmHeight) {
                h = (height - wmHeight) / 2;
            }
            System.out.println("src width=" + Integer.toString(width) + " height=" + Integer.toString(height) + " water width=" + Integer.toString(wmWidth) + " height=" + Integer.toString(wmHeight) + " left=" + Integer.toString(w) + " top=" + Integer.toString(h));

            iWMSrc = iWMSrc.getScaledInstance(wmWidth, wmHeight, 4);

            g.drawImage(iWMSrc, w, h, wmWidth, wmHeight, null);
            g.dispose();
            if (!imageType.equalsIgnoreCase("GIF")) {
                if (imageType.equalsIgnoreCase("JPEG")) {
                    try {
                        JPEGImageWriter imageWriter = (JPEGImageWriter) ImageIO.getImageWritersBySuffix("jpeg").next();
                        ImageOutputStream ios = ImageIO.createImageOutputStream(src);
                        imageWriter.setOutput(ios);

                        JPEGImageWriteParam jpegParams = (JPEGImageWriteParam) imageWriter.getDefaultWriteParam();
                        jpegParams.setCompressionMode(2);
                        jpegParams.setCompressionQuality(0.95F);

                        IIOMetadata data = imageWriter.getDefaultImageMetadata(new ImageTypeSpecifier(bi), jpegParams);

                        imageWriter.write(data, new IIOImage(bi, null, null), jpegParams);
                        ios.close();
                        imageWriter.dispose();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else
                    ImageIO.write(bi, imageType, src);
            } else {
                AnimatedGifEncoder age = new AnimatedGifEncoder();
                age.setQuality(1);
                age.start(src.toString());
                age.addFrame(bi);
                age.finish();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void addWaterMarkForImage(String imageType, File src, File waterMarkSrc, Integer watermarkLeft, Integer watermarkTop) {
        try {
            Image iSrc = ImageIO.read(src);
            int width = iSrc.getWidth(null);
            int height = iSrc.getHeight(null);

            BufferedImage bi = null;
            bi = new BufferedImage(width, height, 1);
            Graphics2D g = bi.createGraphics();
            g.setBackground(Color.WHITE);
            g.fillRect(0, 0, width, height);
            g.drawImage(iSrc, 0, 0, width, height, null);

            Image iWMSrc = ImageIO.read(waterMarkSrc);
            int wmWidth = iWMSrc.getWidth(null);
            int wmHeight = iWMSrc.getHeight(null);
            iWMSrc = iWMSrc.getScaledInstance(wmWidth, wmHeight, 4);

            g.drawImage(iWMSrc, watermarkLeft.intValue(), watermarkTop.intValue(), wmWidth, wmHeight, null);
            g.dispose();

            System.out.println("src width=" + Integer.toString(width) + " height=" + Integer.toString(height) + " water width=" + Integer.toString(wmWidth) + " height=" + Integer.toString(wmHeight) + " left=" + Integer.toString(watermarkLeft.intValue()) + " top=" + Integer.toString(watermarkTop.intValue()));

            if (!imageType.equalsIgnoreCase("GIF")) {
                if (imageType.equalsIgnoreCase("JPEG")) {
                    try {
                        JPEGImageWriter imageWriter = (JPEGImageWriter) ImageIO.getImageWritersBySuffix("jpeg").next();
                        ImageOutputStream ios = ImageIO.createImageOutputStream(src);
                        imageWriter.setOutput(ios);

                        JPEGImageWriteParam jpegParams = (JPEGImageWriteParam) imageWriter.getDefaultWriteParam();
                        jpegParams.setCompressionMode(2);
                        jpegParams.setCompressionQuality(0.95F);

                        IIOMetadata data = imageWriter.getDefaultImageMetadata(new ImageTypeSpecifier(bi), jpegParams);

                        imageWriter.write(data, new IIOImage(bi, null, null), jpegParams);
                        ios.close();
                        imageWriter.dispose();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else
                    ImageIO.write(bi, imageType, src);
            } else {
                AnimatedGifEncoder age = new AnimatedGifEncoder();
                age.setQuality(1);
                age.start(src.toString());
                age.addFrame(bi);
                age.finish();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    static {
        System.setProperty("com.sun.media.jai.disableMediaLib", "true");
    }
    

    /**
     * 剪切图片
     *
     * @param origImage
     * @param xCoordinate
     * @param yCoordinate
     * @param width
     * @param height
     * @return
     * @throws IOException
     */
    public static BufferedImage cropImage(Image origImage, int xCoordinate, int yCoordinate, int width, int height) throws IOException {
        BufferedImage bufferedImage = null;
        try {
            if (origImage == null) return bufferedImage;

            Image croppedImage;
            ImageFilter cropFilter;
            //四个参数分别为图像起点坐标和宽高，即CropImageFilter(int x,int y,int width,int height)，详细情况请参考API
            //指定要裁剪的的文件的宽度和高度，以及起始坐标
            cropFilter = new CropImageFilter(xCoordinate, yCoordinate, width, height);
            //生成图片
            croppedImage = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(origImage.getSource(), cropFilter));
            //生成图像字节流
            bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            bufferedImage.getGraphics().drawImage(croppedImage, 0, 0, width, height, null);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return bufferedImage;


    }
}
